use crate::ast::*;
use crate::error::{CompilerError, Result};
use inkwell::types::BasicType;
use inkwell::values::BasicValueEnum;
use inkwell::AddressSpace;

use super::super::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {
    /// Generate unary expression
    pub(super) fn generate_unary_expression(
        &mut self,
        unary: &UnaryExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        let operand = self.generate_expression(&unary.operand)?;

        match unary.operator {
            UnaryOp::Deref => {
                // Dereference: *ptr -> load the value pointed to
                // Special handling for variables that hold pointers
                if let Expression::Variable(var_name) = &*unary.operand {
                    if let Some(var_value) = self.variable_map.get(var_name) {
                        if var_value.is_pointer_value() {
                            let alloca_ptr = var_value.into_pointer_value();

                            // First, load the pointer from the alloca
                            let ptr_value = self.builder.build_load(
                                self.context.i8_type().ptr_type(AddressSpace::default()),
                                alloca_ptr,
                                &format!("{}_ptr", var_name),
                            )?;

                            if let BasicValueEnum::PointerValue(ptr) = ptr_value {
                                // Get the actual type from variable_type_map
                                if let Some(var_type) = self.variable_type_map.get(var_name) {
                                    let target_type =
                                        match var_type {
                                            Type::Reference(ref_type) => &ref_type.referenced_type,
                                            _ => return Err(CompilerError::internal(
                                                "Cannot dereference non-pointer/reference value",
                                            )),
                                        };
                                    // Check if it's a basic type, struct, or slice
                                    match &**target_type {
                                        Type::Basic(_) => {
                                            // Basic type pointer: load using correct type
                                            let llvm_type = self.nrc_type_to_llvm_type(&Some(
                                                (**target_type).clone(),
                                            ))?;
                                            return Ok(self
                                                .builder
                                                .build_load(llvm_type, ptr, "deref_basic")?
                                                .into());
                                        }
                                        Type::Struct(struct_type) => {
                                            // Struct pointer: load struct
                                            if let Some(struct_decl) =
                                                self.struct_declarations.get(&struct_type.name)
                                            {
                                                let struct_decl = struct_decl.clone();

                                                // Generate LLVM types for fields
                                                let mut field_types = Vec::new();
                                                for field in &struct_decl.fields {
                                                    let field_llvm_type = self
                                                        .nrc_type_to_llvm_type(&Some(
                                                            field.field_type.clone(),
                                                        ))?;
                                                    field_types.push(field_llvm_type.into());
                                                }

                                                let llvm_struct_type =
                                                    self.context.struct_type(&field_types, false);
                                                return Ok(self
                                                    .builder
                                                    .build_load(
                                                        llvm_struct_type,
                                                        ptr,
                                                        "deref_struct",
                                                    )?
                                                    .into());
                                            }
                                        }
                                        Type::Vec(vector_type) => {
                                            // Slice pointer: load slice struct
                                            let element_llvm_type = self.nrc_type_to_llvm_type(
                                                &Some(*vector_type.element_type.clone()),
                                            )?;
                                            let slice_struct_type = self.context.struct_type(
                                                &[
                                                    element_llvm_type
                                                        .ptr_type(AddressSpace::default())
                                                        .into(),
                                                    self.context.i64_type().into(),
                                                    self.context.i64_type().into(),
                                                ],
                                                false,
                                            );
                                            return Ok(self
                                                .builder
                                                .build_load(slice_struct_type, ptr, "deref_slice")?
                                                .into());
                                        }
                                        _ => {}
                                    }
                                }

                                // Fallback: if type not found, try i32
                                return Ok(self
                                    .builder
                                    .build_load(self.context.i32_type(), ptr, "deref")?
                                    .into());
                            }
                        }
                    }
                }

                // Fallback: try to dereference operand directly
                match operand {
                    BasicValueEnum::PointerValue(ptr) => {
                        // Default to i32 if we can't determine the type
                        let i32_type = self.context.i32_type();
                        Ok(self.builder.build_load(i32_type, ptr, "deref")?.into())
                    }
                    _ => Err(CompilerError::internal(
                        "Cannot dereference non-pointer value",
                    )),
                }
            }
            UnaryOp::AddrOf => {
                // Address of: &Type{} -> heap allocation (方案A)
                match &*unary.operand {
                    Expression::Struct(struct_expr) => {
                        // Check if this is a basic type (has special __value__ field)
                        let is_basic_type = struct_expr.fields.len() == 1
                            && struct_expr.fields[0].name == "__value__";

                        if is_basic_type {
                            // Basic type pointer: &int32{100}, &float64{3.14}, etc.
                            let basic_type = &struct_expr.struct_type;

                            // Get the LLVM type
                            let llvm_type =
                                self.nrc_type_to_llvm_type(&Some(basic_type.clone()))?;

                            // Get malloc function (system malloc)
                            let malloc_func =
                                self.module.get_function("malloc").unwrap_or_else(|| {
                                    let malloc_type = self
                                        .context
                                        .i8_type()
                                        .ptr_type(AddressSpace::default())
                                        .fn_type(&[self.context.i64_type().into()], false);
                                    self.module.add_function("malloc", malloc_type, None)
                                });

                            // Calculate size for basic type
                            let size = llvm_type.size_of().ok_or_else(|| {
                                CompilerError::internal("Cannot get size of basic type")
                            })?;

                            // Allocate memory using malloc
                            let ptr = self.builder.build_call(
                                malloc_func,
                                &[size.into()],
                                "malloc_call",
                            )?;
                            let ptr_value = ptr.try_as_basic_value().left().unwrap();

                            // Cast to typed pointer
                            let typed_ptr = match ptr_value {
                                BasicValueEnum::PointerValue(ptr_val) => {
                                    self.builder.build_bitcast(
                                        ptr_val,
                                        llvm_type.ptr_type(AddressSpace::default()),
                                        "typed_ptr",
                                    )?
                                }
                                _ => {
                                    return Err(CompilerError::internal(
                                        "Expected pointer value from malloc",
                                    ))
                                }
                            };

                            let typed_ptr_value = match typed_ptr {
                                BasicValueEnum::PointerValue(ptr) => ptr,
                                _ => {
                                    return Err(CompilerError::internal(
                                        "Expected pointer value from bitcast",
                                    ))
                                }
                            };

                            // Generate and store the value
                            let value = self.generate_expression(&struct_expr.fields[0].value)?;

                            // Cast value to the correct type if needed
                            let casted_value = self.cast_value_to_type(value, llvm_type)?;
                            let _ = self.builder.build_store(typed_ptr_value, casted_value);

                            return Ok(typed_ptr_value.into());
                        }

                        // Struct type pointer: &Person{name: "Alice", age: 30}
                        // Get struct name
                        let struct_name = match &struct_expr.struct_type {
                            Type::Struct(struct_type) => &struct_type.name,
                            Type::Basic(basic_type) => &format!("{:?}", basic_type),
                            Type::Generic(name) => name,
                            _ => "unknown",
                        };

                        // Look up the struct type definition
                        if let Some(struct_decl) = self.struct_declarations.get(struct_name) {
                            let struct_decl = struct_decl.clone();

                            // Generate LLVM types for each field
                            let mut field_types = Vec::new();
                            for field in &struct_decl.fields {
                                let field_llvm_type =
                                    self.nrc_type_to_llvm_type(&Some(field.field_type.clone()))?;
                                field_types.push(field_llvm_type.into());
                            }

                            let struct_type = self.context.struct_type(&field_types, false);

                            // Get malloc function (system malloc)
                            let malloc_func =
                                self.module.get_function("malloc").unwrap_or_else(|| {
                                    let malloc_type = self
                                        .context
                                        .i8_type()
                                        .ptr_type(AddressSpace::default())
                                        .fn_type(&[self.context.i64_type().into()], false);
                                    self.module.add_function("malloc", malloc_type, None)
                                });

                            // Calculate struct size
                            let size = struct_type.size_of().unwrap();

                            // Allocate memory using malloc
                            let ptr = self.builder.build_call(
                                malloc_func,
                                &[size.into()],
                                "malloc_call",
                            )?;
                            let ptr_value = ptr.try_as_basic_value().left().unwrap();

                            // Cast to struct pointer
                            let struct_ptr = match ptr_value {
                                BasicValueEnum::PointerValue(ptr_val) => {
                                    self.builder.build_bitcast(
                                        ptr_val,
                                        struct_type.ptr_type(AddressSpace::default()),
                                        "struct_ptr",
                                    )?
                                }
                                _ => {
                                    return Err(CompilerError::internal(
                                        "Expected pointer value from malloc",
                                    ))
                                }
                            };

                            let struct_ptr_value = match struct_ptr {
                                BasicValueEnum::PointerValue(ptr) => ptr,
                                _ => {
                                    return Err(CompilerError::internal(
                                        "Expected pointer value from bitcast",
                                    ))
                                }
                            };

                            // Initialize fields with provided values or defaults
                            for field_init in &struct_expr.fields {
                                // Find the field index
                                let field_index = struct_decl
                                    .fields
                                    .iter()
                                    .position(|field| field.name == field_init.name)
                                    .ok_or_else(|| {
                                        CompilerError::internal(&format!(
                                            "Unknown field: {}",
                                            field_init.name
                                        ))
                                    })?;

                                // Generate the field value
                                let field_value = self.generate_expression(&field_init.value)?;

                                // Get field pointer
                                let field_ptr = unsafe {
                                    self.builder.build_gep(
                                        struct_type,
                                        struct_ptr_value,
                                        &[
                                            self.context.i32_type().const_int(0, false),
                                            self.context
                                                .i32_type()
                                                .const_int(field_index as u64, false),
                                        ],
                                        &format!("field_{}_ptr", field_init.name),
                                    )?
                                };

                                // Store the field value
                                let _ = self.builder.build_store(field_ptr, field_value);
                            }

                            // Initialize remaining fields with default values
                            for (idx, field) in struct_decl.fields.iter().enumerate() {
                                // Check if this field was already initialized
                                if !struct_expr.fields.iter().any(|f| f.name == field.name) {
                                    // Get default value for this field type
                                    if let Some(default_lit) = field.field_type.default_value() {
                                        let default_value = self.generate_literal(&default_lit)?;

                                        // Get field pointer
                                        let field_ptr = unsafe {
                                            self.builder.build_gep(
                                                struct_type,
                                                struct_ptr_value,
                                                &[
                                                    self.context.i32_type().const_int(0, false),
                                                    self.context
                                                        .i32_type()
                                                        .const_int(idx as u64, false),
                                                ],
                                                &format!("field_{}_ptr", field.name),
                                            )?
                                        };

                                        // Store the default value
                                        let _ = self.builder.build_store(field_ptr, default_value);
                                    }
                                }
                            }

                            Ok(struct_ptr_value.into())
                        } else {
                            Err(CompilerError::internal(&format!(
                                "Struct declaration not found: {}",
                                struct_name
                            )))
                        }
                    }
                    Expression::Variable(var_name) => {
                        // Convert value to pointer: &variable
                        // Return the alloca pointer of the variable (don't load the value)
                        if let Some(var_ptr) = self.variable_map.get(var_name) {
                            // The variable_map stores alloca pointers
                            // For &variable, we want to return this pointer
                            Ok((*var_ptr).into())
                        } else {
                            Err(CompilerError::internal(&format!(
                                "Variable not found: {}",
                                var_name
                            )))
                        }
                    }
                    Expression::IndexAccess(_) | Expression::FieldAccess(_) => {
                        // For array/slice element or struct field access, we need to get the address
                        // This is more complex and requires special handling
                        // For now, generate the expression normally, which should give us the value
                        // Then we need to create a temporary and return its address
                        let value = self.generate_expression(&unary.operand)?;

                        // Create a temporary alloca to hold this value
                        let value_type = value.get_type();
                        let temp_alloca = self.builder.build_alloca(value_type, "temp_for_addr")?;
                        let _ = self.builder.build_store(temp_alloca, value);

                        Ok(temp_alloca.into())
                    }
                    _ => {
                        // For other expressions, create a temporary and return its address
                        let value = self.generate_expression(&unary.operand)?;

                        // Create a temporary alloca to hold this value
                        let value_type = value.get_type();
                        let temp_alloca = self.builder.build_alloca(value_type, "temp_for_addr")?;
                        let _ = self.builder.build_store(temp_alloca, value);

                        Ok(temp_alloca.into())
                    }
                }
            }
            UnaryOp::Neg => {
                // Unary minus: -x
                match operand {
                    BasicValueEnum::IntValue(int_val) => {
                        // CRITICAL FIX: Use the operand's type, not hardcoded i32!
                        let int_type = int_val.get_type();
                        let zero = int_type.const_int(0, false);
                        Ok(self.builder.build_int_sub(zero, int_val, "neg")?.into())
                    }
                    BasicValueEnum::FloatValue(float_val) => {
                        let zero = self.context.f64_type().const_float(0.0);
                        Ok(self
                            .builder
                            .build_float_sub(zero, float_val, "fneg")?
                            .into())
                    }
                    _ => Err(CompilerError::internal("Cannot negate non-numeric value")),
                }
            }
            UnaryOp::Pos => {
                // Unary plus: +x (no-op)
                Ok(operand)
            }
            UnaryOp::Not => {
                // Logical not: !x
                match operand {
                    BasicValueEnum::IntValue(int_val) => {
                        // Get the type of the integer value to create the correct zero constant
                        let int_type = int_val.get_type();
                        let zero = int_type.const_int(0, false);
                        let is_zero = self.builder.build_int_compare(
                            inkwell::IntPredicate::EQ,
                            int_val,
                            zero,
                            "is_zero",
                        )?;
                        Ok(self
                            .builder
                            .build_int_z_extend(is_zero, self.context.i32_type(), "not")?
                            .into())
                    }
                    _ => Err(CompilerError::internal(
                        "Cannot apply logical not to non-integer value",
                    )),
                }
            }
            UnaryOp::BitNot => {
                // Bitwise not: ~x
                match operand {
                    BasicValueEnum::IntValue(int_val) => {
                        // Create all-ones value matching the operand's bit width
                        let int_type = int_val.get_type();
                        let all_ones = int_type.const_all_ones();
                        Ok(self.builder.build_xor(int_val, all_ones, "bitnot")?.into())
                    }
                    _ => Err(CompilerError::internal(
                        "Cannot apply bitwise not to non-integer value",
                    )),
                }
            }
        }
    }
}
